/***************************************************************************//**
 * @file mac_fhss.c
 * @brief for mac 
 * @author ze .
 * @date  2022/7/03.
 * @copyright Copyright 
 ******************************************************************************/
#include"mac_fhss.h"
#include "mac_timeSync.h"
#include "softwareMultiTimer.h"
#include "mac_packetHandle.h"
#include "device.h"

static uint32_t s_seed;
static uint8_t pbyHopSeq[RF_CHANNEL_HOP_SEQ_LEN];
static uint8_t byResyncChan = RF_CHAN_RESYNC_DEFAULT_NUMBER ;// 备用信道
//static uint8_t byMainChan = 0;  // 主信道，每400ms更新一次
static uint8_t sRfChanNumMax = RF_CHAN_NUM_868MHZ;

void srand_(uint32_t seed)
{
    s_seed = seed;
}

uint16_t rand_(void)
{
    return(((s_seed = s_seed * 214013L
        + 2531011L) >> 16) & 0x7fff );    
}

void initFhssSequence(uint32_t dwSystemId, uint8_t byOffset)
{
//    uint8_t count[20] ={0,};
    int i=0,j=0;
    uint32_t temp32 = 0;
    RF_FREQ_EN eFreq = getDeviceRfFreq();
    switch(eFreq)
    {
      case RF_FREQ_868MHZ:
        sRfChanNumMax = RF_CHAN_NUM_868MHZ;
      break;

      case RF_FREQ_915MHZ:
        sRfChanNumMax = RF_CHAN_NUM_915MHZ;
      break;

      case RF_FREQ_433MHZ:
        sRfChanNumMax = RF_CHAN_NUM_433MHZ;
      break;

      case RF_FREQ_915MHZ_RCM:
        sRfChanNumMax = RF_CHAN_NUM_915MHZ_RCM;
      break;

      case RF_FREQ_868MHZ_WPC:
        sRfChanNumMax = RF_CHAN_NUM_433MHZ_WPC;
      break;

      default:
        sRfChanNumMax = RF_CHAN_NUM_868MHZ;
        break;
    }
    srand_(dwSystemId);//ToDo
    for(i=0; i<RF_CHANNEL_HOP_SEQ_LEN; i++)
    {
        pbyHopSeq[i] = rand_() % sRfChanNumMax;
        if(i>0)
        {
            if(pbyHopSeq[i] == pbyHopSeq[i-1])
            {
                do
                {
                   j++; 
                   pbyHopSeq[i] = rand_() % sRfChanNumMax;
                } while (pbyHopSeq[i] == pbyHopSeq[i-1] && j<100); //是否统计次数，超次数退出
            }

            temp32 = (uint32_t)pbyHopSeq[i] + (uint32_t)byOffset; 
            if(temp32 >= sRfChanNumMax)
            {
                temp32 = temp32 - sRfChanNumMax;
            }
            pbyHopSeq[i] = temp32;
        }
        //printf("HopCHan%d:%d\r\n",i,pbyHopSeq[i]);
//        count[pbyHopSeq[i]] ++;
    }

//    for(i=0;i<20;i++){
//        printf("ch%d:%d\r\n",i,count[i]);
//    }
}

//ToDo 可改造成下述 getNextMainChanUpdateTimerDeadLine if else 提高效率？？ 待测试
uint8_t autoCalculateMainChan(void)
{
    uint32_t temp32;
    uint8_t temp8;
#ifdef RF_CHAN_FREQ_HOP_ENABLE
    /*
    temp32 = ( READ_BU_RTC_COUNT() & 0xFFFFFF) >> 13; //bug 精度损失严重，bug 0809
    temp32 = (temp32 * 10) / 16;
    */
    //temp32 = (READ_BU_RTC_COUNT() & 0xFFFFFF) / (32768*0.4)
    temp32 = ((READ_BU_RTC_COUNT() & 0x00FFFFFF) * 5) >> 16; //ToDo 可考虑先左移2，+ 自身
    temp8 = temp32 % RF_CHANNEL_HOP_SEQ_LEN; //有该步骤，以及时间同步的长度为3字节，因此，时间可&0xFFFFFF
    return pbyHopSeq[temp8];
#else
    return RF_CHAN_NO_HOP_FIXED_UNMBER;  //若不使能 FHSS，则默认0信道
#endif
}

//+- RFM_HUB_SYNC_ERROR_MID_TOLERANCE  +-327 GAP切换时隙保护,TDMA 例外slot
uint32_t getNextMainChanUpdateTimerDeadLine()//每400ms产生1次超时 进行主信道切换，判断以节省时间
{
  uint32_t temp32;

  temp32 = READ_BU_RTC_COUNT();
  temp32 = temp32 & 0x0000FFFF;

  if(temp32 >= 52429) //52102 - 52756  //327 10ms间隙
  {
      temp32 = 65536;
  }
  else if(temp32 >= 39321)//38994 - 39648
  {
      temp32 = 52429;
  }
  else if(temp32 >= 26214) //25887 - 26541
  {
      temp32 = 39321;
  }
  else if(temp32 >= 13107) //12780 - 13434
  {
      temp32 = 26214;
  }
  else if(temp32 >= 0)//TDMA 保护时隙 与广播窗口重合 65209 - 327
  {
      temp32 = 13107;
  }
  //printf(":%u",temp32);
  return temp32;

}

// 1 main,2 sync
uint8_t getAccessChan(CHAN_TYPE_E type)
{
  if(type == CHAN_TYPE_MAIN)
  {
    if(isTimeSynced())
    {
        return autoCalculateMainChan(); //ToDo，后续可不用每次重新计算
    }
    else
    {
        return byResyncChan;
    }
  }
  else if(type == CHAN_TYPE_RESYNC)
  {
      return byResyncChan; //
  }
  return byResyncChan; //
}
